using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using NetProtocol.Enum;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class LevelPlayModule : Singleton<LevelPlayModule>, IGameplaySceneArea
    {

        /// <summary>
        /// 当前是否在玩法中
        /// </summary>
        public bool inLevelPlay { get; private set; }
        /// <summary>
        /// 是否当前不仅进入关卡且准备完毕
        /// </summary>
        public bool isSceneReady => inLevelPlay && levelPlay.isSceneReady;
        public LevelPlayController levelPlay { private set; get; }
        public GameplayAreaType areaType => GameplayAreaType.Level;
        public int curRegionCid => levelPlay.regionCtrl.levelRegion.cid;
        public TNavigationController navigationCtrl => levelPlay.regionCtrl.navigationCtrl;
        /// <summary>
        /// 切换场景的任务
        /// </summary>
        private AutoResetUniTaskCompletionSource _changeRegionTaskSource;

        protected LevelPlayModule()
        {

        }

        public async UniTask OnEnter(object userData)
        {
            //ClearLevelPlay(); // 可能未成功收到服务器的离开协议，然后又进入了新关卡
            if (inLevelPlay)
            {
                return;
            }
            (int levelId, bool isLocal) = (ValueTuple<int, bool>)userData;
            var cfgLevel = TableCenter.level.Get(levelId);
            if (cfgLevel == null)
            {
                LogGame.LogError("level cfg is null,id:" + levelId);
                return;
            }
            inLevelPlay = true;
            levelPlay = new LevelPlayController();
            if (!levelPlay.InitLevelController(cfgLevel))
            {
                return;
            }
            if (isLocal)
            {
                await levelPlay.PrepareLocalLevel();
            }
        }

        public void OnLeave()
        {
            if (!inLevelPlay)
            {
                return;
            }
            inLevelPlay = false;
            ClearLevelPlay();
        }

        private void ClearLevelPlay()
        {
            levelPlay?.Dispose();
            levelPlay = null;
            BattleManager.Instance.Dispose();
        }

        public TViewEntity GetPlayerAvatarEntity()
        {
            if (!isSceneReady)
            {
                return null;
            }
            return levelPlay.regionCtrl.entityCtrl.GetMainCharacter();
        }

        public TViewEntity GetEntityByMcid(int id)
        {
            if (!isSceneReady)
            {
                return null;
            }
            return levelPlay.regionCtrl.entityCtrl.GetEntityByMcid(id);
        }

        public TViewEntity GetEntityById(int id)
        {
            if (!isSceneReady)
            {
                return null;
            }
            if (levelPlay.regionCtrl.entityCtrl.entitys.TryGetValue(id, out var entity))
            {
                return entity;
            }
            return null;
        }

        public void SearchEntities(List<TViewEntity> result, Func<TViewEntity, bool> searchFunc)
        {
            if (result == null || searchFunc == null)
            {
                LogGame.LogError("参数result和searchFunc均不能为空");
                return;
            }
            if (!isSceneReady)
            {
                return;
            }
            foreach (var entity in levelPlay.regionCtrl.entityCtrl.entitys.Values)
            {
                if (searchFunc(entity))
                {
                    result.Add(entity);
                }
            }
        }

        public void GetEntitiesAround(List<TViewEntity> entities, float radius)
        {
            if (!isSceneReady)
            {
                return;
            }
            levelPlay.regionCtrl.entityCtrl.GetMainCharacter().GetTransformPosXZ(out var x, out var z);
            var area = GameMathUtil.GetRectRangeV2(x, z, radius);
            List<LevelPlayBaseEntity> lvEntities = ListPool<LevelPlayBaseEntity>.Get();
            levelPlay.regionCtrl.entityCtrl.QTRetrieveObjects(lvEntities, area);
            foreach (var e in lvEntities)
            {
                entities.Add(e);
            }
            ListPool<LevelPlayBaseEntity>.Put(lvEntities);
        }

        public bool IsPlayerMoving()
        {
            if (!isSceneReady)
            {
                return false;
            }
            var state = levelPlay.regionCtrl.interactCtrl.stateOperational;
            return state != null && state.active && state.isMoving;
        }

        public TViewEntity GetTrackingEntity()
        {
            if (!isSceneReady)
            {
                return null;
            }
            var entityId = levelPlay.levelPlayer.manualTrackingEntity;
            if (entityId == 0)
            {
                return null;
            }
            if (levelPlay.regionCtrl.entityCtrl.entitys.TryGetValue(entityId, out var entity))
            {
                return entity;
            }
            return null;
        }

        public async UniTask MarkTrackingEntity(int entityId)
        {
            if (!isSceneReady)
            {
                return;
            }
            var result = await CLevelLogicModule.NetCore.CS_MarkTrackingEntity(entityId);
            if (result.IsFail)
            {
                LogGame.LogError("标记跟踪实体失败，code：" + result.code);
                return;
            }
            levelPlay.levelPlayer.manualTrackingEntity = entityId;
            var playerEntity = levelPlay.regionCtrl.entityCtrl.GetMainCharacter();
            if (playerEntity == null)
            {
                LogGame.LogError("找不到玩家实体");
                return;
            }
            await GameScenePlayUtil.ShowEntityTrack();
        }

        public async UniTask TeleportToRegion(int regionCid, int portalId)
        {
            if (!isSceneReady)
            {
                return;
            }
            //请求切换场景
            var result = await CLevelLogicModule.NetCore.CS_EnterRegion(regionCid, portalId);
            if (result.IsFail)
            {
                return;
            }
            //创建等待任务
            _changeRegionTaskSource = AutoResetUniTaskCompletionSource.Create();
            await _changeRegionTaskSource.Task;
        }

        public void CompleteChangeRegionTask(bool isOK)
        {
            if (_changeRegionTaskSource != null)
            {
                // 注意！这里要先置空，再调用，TrySetResult会先调用await之后的代码，如果await之后有给TaskSource赋新值，然后这里再置空，那么_completeActTaskSource就永远为null了
                var ts = _changeRegionTaskSource;
                _changeRegionTaskSource = null;
                if (isOK)
                {
                    ts.TrySetResult();
                }
                else
                {
                    ts.TrySetCanceled();
                }
            }
        }

        public async UniTask<bool> SwitchPhasing(GameScenePhasing phasing, Vector3 mainPhasingPos = default)
        {
            if (!isSceneReady)
            {
                return false;
            }
            return await levelPlay.SwitchPhasing(phasing, mainPhasingPos);
        }

        void IGameplaySceneArea.ChangeDisplayTime(int hour24)
        {
            LogGame.LogError("关卡不支持手动修改时间，仅可由内部功能决定。");
        }

        public (bool, int) CheckCondition(int conditionCid, TViewEntity interactingEntity)
        {
            if (!isSceneReady)
            {
                return (false, 0);
            }
            if (interactingEntity != null && interactingEntity is not LevelPlayBaseEntity)
            {
                LogGame.LogError($"参数interactingEntity不是当前模块的类型（{nameof(LevelPlayBaseEntity)}）");
                return (false, 0);
            }
            (bool, int) result;
            var blackboard = ClassPool<ConditionBlackboard>.Get();
            {
                blackboard.enviroment = levelPlay.regionCtrl.entityCtrl;
                blackboard.curPlayer = levelPlay.levelPlayer;
                blackboard.curEntity = (IConditionPropFetcher)interactingEntity;
                result = ConditionModule.Instance.Check(conditionCid, blackboard);
            }
            ClassPool<ConditionBlackboard>.Put(blackboard);
            return result;
        }
    }
}
